/*******************************************************************************
 * Copyright (c) 2013 University of Luxembourg and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     @author Qin ZHANG ("Jackin" as a Global Communication ID)
 ******************************************************************************/

package lu.uni.geko.ext.ram;

import lu.uni.geko.common.AbstractModelTransformer;
import lu.uni.geko.common.GeKoConstants;
import lu.uni.geko.resources.MainResourceLoader;
import lu.uni.geko.util.bridges.EMFBridge;

import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;

import ram.Aspect;
import ram.Instantiation;

/**
 * @author Jackin
 * 
 *         This is an extended weaver for TouchRAM.
 */
public final class WeaverExt extends AbstractModelTransformer<URI>
{
	/** The URI of the woven base model. */
	private URI wovenMURI;

	public WeaverExt(final URI baseMURI)
	{
		super(baseMURI);
		this.wovenMURI = EMFBridge.newURIWithStringAppendedToFilename(baseMURI, GeKoConstants.getWovenMFilenameAppendage());
	}

	@Override
	public URI transform()
	{
		// for (JoinPoint joinPoint : this.joinPoints) {
		// Advice advice =
		// AdviceAndScopeResolver.resolveAvAndInstantiationScopes(this.adviceMURI);
		// AdviceEffectuation adviceEffectuation =
		// AdviceEffectuationCalculator.calculateAdviceEffectuation(joinPoint,
		// advice,
		// this.pc2AvN2NMap);
		// getConsole().println("\nInspecting join point: " + joinPoint + "\n");
		// getConsole().println("Advice:\n" + advice + "\n");
		// getConsole().println("AdviceEffectuation:\n" + adviceEffectuation +
		// "\n");
		// Merger merger = new Merger(advice, adviceEffectuation, this.wovenMURI);
		// FeatureEquivalenceHelper featureEquivalenceHelper =
		// merger.performMergesAndReturnFeatureEquivalenceHelper();
		// MainAdder.performAdditions(advice, adviceEffectuation,
		// featureEquivalenceHelper, this.wovenMURI);
		// Remover.performRemovals(adviceEffectuation);
		// }
		// getConsole().println("\nFinished weaving at all " + joinPoints.size() +
		// " join points.\n");
		// getConsole().print("Saving woven model ...");
		// MainResourceLoader.save(wovenMURI);
		getConsole().println(" done");
		return this.wovenMURI;
	}

	/**
	 * Extension for TouchRAM model weaving.
	 * 
	 * @param baseMURI
	 *          the URI of the base model (RAM aspect)
	 * @return the URI of the woven model
	 * @throws Exception 
	 */
	public final URI weave(final URI baseMURI)
	{
		/*
		 * The first step is to load the base model (RAM aspect).
		 */
		Aspect base = (Aspect) MainResourceLoader.getUniqueContentRoot(this.getMURI(), "base model");
		
		/*
		 * The second step is to weave recursively, according to the instantiations.
		 */
		EList<Instantiation> instantiations = base.getInstantiations();
		for (int i=0; i<instantiations.size(); i++)
		{
			Instantiation instantiation = instantiations.get(i);
			
			// "dependent" is an external aspect which the base aspect is depending on.
			Aspect dependent = (Aspect) instantiation.getExternalAspect();
			try
			{
				if (dependent.getStructuralView()==null)
				{
					// According to RAM, any aspect must have one structural view.
					// If the structural view is null, that means the expected aspect is not found.
					throw new Exception("Cannot find the dependent RAM aspect: "+dependent.toString());
				}
			}
			catch (Exception ex)
			{
				System.err.println(ex);
				break;
			}
			
			// Change the element names in the dependent aspect,
			// if the instantiation type is "depends", according to RAM metamodel.
			// The instantiation type "extends" is the default GeKo mode.
			if (instantiation.getType().getLiteral().equalsIgnoreCase(RamConstants.INSTANTIATION_TYPE_DEPENDS))
			{
				RamUtil.instantiate(dependent, instantiation);
			}

			
		}

		

		/*
		 * The first step is to re-organize the RAM aspect (baseMURI) to fetch
		 * external dependencies (other RAM aspects would be woven later on), to
		 * identify exact base, pointcut and advice models from RAM-specific format
		 * to GeKo generic format.
		 * 
		 * Note that since the external dependencies may be multiple, the weaving
		 * process should be an iteration.
		 */

		this.wovenMURI = transform();

		// Weaver weaver = new Weaver(baseMURI, avMURI, pc2AvN2NMap);
		// URI wovenMURI = weaver.copyBaseToWovenMURI();
		// List<JoinPoint> joinPoints = detectJoinpoints(pcMURI, wovenMURI);
		// weaver.setJoinPoints(joinPoints);
		// weaver.transform();

		return this.wovenMURI;
	}

}
